package com.googlecode.battleofendor.jme;

import java.util.logging.Level;
import java.util.logging.Logger;

import jmetest.effects.water.TestProjectedWater;

import com.googlecode.battleofendor.ClientLauncher;
import com.googlecode.battleofendor.synchroniation.Player;
import com.googlecode.battleofendor.synchroniation.SceneGraph;
import com.googlecode.battleofendor.synchroniation.messages.PositionInfo;
import com.jme.app.SimpleGame;
import com.jme.app.SimplePassGame;
import com.jme.bounding.BoundingBox;
import com.jme.bounding.BoundingSphere;
import com.jme.image.Texture;
import com.jme.input.AbsoluteMouse;
import com.jme.input.KeyInput;
import com.jme.input.controls.GameControl;
import com.jme.input.controls.GameControlManager;
import com.jme.input.controls.binding.KeyboardBinding;
import com.jme.input.controls.binding.MouseAxisBinding;
import com.jme.input.controls.binding.MouseButtonBinding;
import com.jme.input.controls.binding.MouseOffsetBinding;
import com.jme.input.controls.controller.ActionController;
import com.jme.input.controls.controller.Axis;
import com.jme.input.controls.controller.GameControlAction;
import com.jme.input.controls.controller.RotationController;
import com.jme.light.PointLight;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.CameraNode;
import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jme.scene.Skybox;
import com.jme.scene.Spatial;
import com.jme.scene.TriMesh;
import com.jme.scene.Spatial.LightCombineMode;
import com.jme.scene.Spatial.TextureCombineMode;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Cylinder;
import com.jme.scene.shape.Sphere;
import com.jme.scene.state.CullState;
import com.jme.scene.state.FogState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.MaterialState;
import com.jme.scene.state.ZBufferState;
import com.jme.util.TextureManager;
import com.jme.util.resource.ResourceLocatorTool;
import com.jme.util.resource.SimpleResourceLocator;
import com.jmex.effects.TrailMesh;

public class BattleOfEndor extends SimpleGame {
	
	Player player;
	
	/**
	 * @param args Kommandozeilenargumente werden ignoriert.
	 */
	public BattleOfEndor(Player player) {
		this.player = player;
	}
	
	LightState ls;
	
	MaterialState ms;
	
	Node n;
	
	@Override
	protected void simpleInitGame() {
		// Create our objects. Nothing new here.
		Box b = new Box("My box", new Vector3f(1, 1, 1), new Vector3f(2, 2, 2));
		b.setModelBound(new BoundingBox());
		b.updateModelBound();
		Sphere s = new Sphere("My sphere", 15, 15, 1);
		s.setModelBound(new BoundingSphere());
		s.updateModelBound();
		n = new Node("My root node");
 
		// Get a MaterialState
		ms = display.getRenderer().createMaterialState();
		// Give the MaterialState an emissive tint
		ms.setEmissive(new ColorRGBA(1f, .0f, 0f, 1));
 
		// Create a point light
		PointLight l = new PointLight();
		// Give it a location
		l.setLocation(new Vector3f(0, 10, 5));
		// Make it a red light
		l.setDiffuse(ColorRGBA.red.clone());
		// Enable it
		l.setEnabled(true);
 
		// Create a LightState to put my light in
		ls = display.getRenderer().createLightState();
		// Attach the light
		//ls.attach(l);
		// ls.setGlobalAmbient(ColorRGBA.white);
		
		// Signal that b should use renderstate ts
		// Signal that n should use renderstate ms
		n.setRenderState(ms);
		// Detach all the default lights made by SimpleGame
		//lightState.detachAll();
		// Make my light effect everything below node n
		//n.setRenderState(ls);
 
		// Attach b and s to n, and n to rootNode.
		n.attachChild(b);
		n.attachChild(s);
		rootNode.attachChild(n);

		
		buildCoords();
			
		buildCamControl();
		
		buildSkyBox();
	    
	    buildCanon();
	}
	
	public SceneGraph getSceneGraph() {
		return new SceneGraph() {
			@Override
			public void add(PositionInfo info) {
				System.out.println("Adding object.");
				if(info.type.equals("laser")) {
					Sphere bullet = new Sphere(info.name, 8, 8, .1f);
		            bullet.setModelBound(new BoundingSphere());
		            bullet.updateModelBound();
		            /** Move bullet to the camera location */
		            bullet.setLocalTranslation(info.x, info.y, info.z);
		            /**
		             * Update the new world locaion for the bullet before I add a
		             * controller
		             */
		            bullet.updateGeometricState(0, true);
		            /**
		             * Add a movement controller to the bullet going in the camera's
		             * direction
		             */
		            bullet.addController(new LinearPoolMover(bullet, player));
		            n.attachChild(bullet);
		            bullet.updateRenderState();
				} else if(info.type.equals("player")) {
					Sphere s = new Sphere(info.name, 10, 10, 10.0f);
					s.updateRenderState();
					s.addController(new LinearPoolMover(s, player));
					rootNode.attachChild(s);
				}
			}
		};
	}
	
	private void buildCoords() {
		for(int i=0; i < 100; i++) {
			Sphere s = new Sphere("SphereA" + i, 10, 10, 1f);
			s.setLocalTranslation(new Vector3f(0.0f, 0.0f, 2.0f * i));
			s.setModelBound(new BoundingBox());
			s.updateModelBound();
			s.setRandomColors();
			s.updateRenderState();
			rootNode.attachChild(s);
		}
		
		for(int i=0; i < 100; i++) {
			Sphere s = new Sphere("SphereB" + i, 10, 10, 1f);
			s.setLocalTranslation(new Vector3f(2.0f * i, 0.0f, 0.0f));
			s.setModelBound(new BoundingBox());
			s.updateModelBound();
			s.setRandomColors();
			rootNode.attachChild(s);
		}
		
		for(int i=0; i < 100; i++) {
			Sphere s = new Sphere("SphereC" + i, 10, 10, 1f);
			s.setLocalTranslation(new Vector3f(0.0f, 2.0f * i, 0.0f));
			s.setModelBound(new BoundingBox());
			s.updateModelBound();
			s.setRandomColors();
			rootNode.attachChild(s);
		}
		
		for(int i=0; i < 100; i++) {
			Sphere s = new Sphere("SphereDiagonal" + i, 10, 10, 1f);
			s.setLocalTranslation(new Vector3f(1.4f * i, 1.4f * i, 1.4f * i));
			s.setModelBound(new BoundingBox());
			s.updateModelBound();
			s.setRandomColors();
			rootNode.attachChild(s);
		}

	}
	
	CameraNode camera;
	
	GameControlManager manager;
	
	private void buildCamControl() {
		camera = new CameraNode("Cam" + Math.random(), cam);
		camera.setLocalTranslation(40, 10, 10);
		rootNode.attachChild(camera);
		
		manager = new GameControlManager();
		GameControl rollLeft = manager.addControl("Roll Left");
	    rollLeft.addBinding(new MouseOffsetBinding(MouseAxisBinding.AXIS_X, false));

	    GameControl rollRight = manager.addControl("Roll Right");
	    rollRight.addBinding(new MouseOffsetBinding(MouseAxisBinding.AXIS_X, true));
	    
	    GameControl rollUp = manager.addControl("Roll Up");
	    rollUp.addBinding(new MouseOffsetBinding(MouseAxisBinding.AXIS_Y, true));
	    
	    GameControl rollDown = manager.addControl("Roll down");
	    rollDown.addBinding(new MouseOffsetBinding(MouseAxisBinding.AXIS_Y, false));
	    
	    GameControl rollWith = manager.addControl("Roll With");
	    rollWith.addBinding(new KeyboardBinding(KeyInput.KEY_A));
	    
	    GameControl rollAgainst = manager.addControl("Roll With");
	    rollAgainst.addBinding(new KeyboardBinding(KeyInput.KEY_D));
	    
	    if(!ClientLauncher.isClient) {
	    RotationController rollXControl = new RotationController(camera, rollRight,
                rollLeft, 0.5f, Axis.Y);
	    camera.addController(rollXControl);
    
	    RotationController rollYControl = new RotationController(camera, rollUp, rollDown, 0.5f, Axis.X);
	    camera.addController(rollYControl);
    
	    RotationController rollZControl = new RotationController(camera, rollWith, rollAgainst, 0.5f, Axis.Z);
	    camera.addController(rollZControl); }
	    
	    player.createSharedPositionInfo(camera, "player", cam.getDirection(), 10);
	}
	
	Skybox sb;
	
	private void buildSkyBox() {
		sb = new Skybox("skybox", 400, 400, 400);
		 
		String dir = "";
		Texture north = TextureManager.loadTexture(TestProjectedWater.class
                .getClassLoader().getResource(dir + "behind.jpg"),
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear);
        Texture south = TextureManager.loadTexture(TestProjectedWater.class
                .getClassLoader().getResource(dir + "top.jpg"),
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear);
        Texture east = TextureManager.loadTexture(TestProjectedWater.class
                .getClassLoader().getResource(dir + "top.jpg"),
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear);
        Texture west = TextureManager.loadTexture(TestProjectedWater.class
                .getClassLoader().getResource(dir + "top.jpg"),
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear);
        Texture up = TextureManager.loadTexture(TestProjectedWater.class
                .getClassLoader().getResource(dir + "top.jpg"),
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear);
        Texture down = TextureManager.loadTexture(TestProjectedWater.class
                .getClassLoader().getResource(dir + "top.jpg"),
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear);

        Skybox skybox = sb;
        skybox.setTexture(Skybox.Face.North, north);
        skybox.setTexture(Skybox.Face.West, west);
        skybox.setTexture(Skybox.Face.South, south);
        skybox.setTexture(Skybox.Face.East, east);
        skybox.setTexture(Skybox.Face.Up, up);
        skybox.setTexture(Skybox.Face.Down, down);
        skybox.preloadTextures();
 
		CullState cullState = display.getRenderer().createCullState();
		cullState.setCullFace(CullState.Face.None);
		cullState.setEnabled(true);
		sb.setRenderState(cullState);
 
		sb.updateRenderState();
		
		rootNode.attachChild(sb);
    }
	
	ActionController canon;
	
	private void buildCanon() {
		GameControl fireBullet = manager.addControl("Fire Bullet");
	    fireBullet.addBinding(new MouseButtonBinding(MouseButtonBinding.LEFT_BUTTON));
	    fireBullet.addBinding(new KeyboardBinding(KeyInput.KEY_F));
	    
	    
	    canon = new ActionController(fireBullet, new GameControlAction() {
	    	private int numBullets;
	    	
			@Override
			public void pressed(GameControl control, float time) {
				Sphere bullet = new Sphere("bullet" + numBullets++, 8, 8, .1f);
	            
	            bullet.setModelBound(new BoundingSphere());
	            bullet.updateModelBound();
	            /** Move bullet to the camera location */
	            bullet.setLocalTranslation(new Vector3f(camera.getLocalTranslation()));
	            /**
	             * Update the new world locaion for the bullet before I add a
	             * controller
	             */
	            bullet.updateGeometricState(0, true);
	            /**
	             * Add a movement controller to the bullet going in the camera's
	             * direction
	             */
	            player.createSharedPositionInfo(bullet, "laser", cam.getDirection(), 100);
	            
	            bullet.addController(new LinearPoolMover(bullet, player));
	            
	            
	            n.attachChild(bullet);
	            
	            bullet.updateRenderState();
	            
	            Logger.getLogger("test").log(Level.INFO, "FIRE!");
			}
			@Override
			public void released(GameControl control, float time) {
			}
	    });
	}
	
	@Override
	protected void simpleUpdate() {
		camera.setLocalTranslation(camera.getLocalTranslation().add(camera.getCamera().getDirection().mult(tpf * 10)));
		PositionInfo camInfo = player.getPositionInfo(camera.getName());
		camInfo.type = "player";
		camInfo.speed = 1;

		camInfo.setDirection(cam.getDirection());
		camInfo.setLocation(camera.getLocalTranslation());
		
		canon.update(tpf);
	}


}
